package org.lmib.abt.checkers;
/*
 * Copyright (c) 1996/1997 F. Di Fabio
 * All rights reserved.
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc., 675
 * Mass Ave, Cambridge, MA 02139, USA.
 */

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.CardLayout;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Choice;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Label;
import java.awt.List;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;

public class CheckersBoard extends Applet {
  State state;
  int playerColor;
  int computerColor;
  boolean editMode;
  Vector listOfMoves;
  Vector listOfCompMoves;
  Move playerMove;
  Move computerMove;
  Move cur;
  int maxPly; 
  boolean gameStarted;
  Image images[];
  Vector boxSelected;
  boolean helpOn;
  
  //dialog componentes
  private Label lblTitle;
  private Label lblStatus;
  private Label lblHelpMoves;
  private CanvasCheckersBoard cnvBoard;
  private Panel pnlCanvas;
  private Panel pnlLevel;
  private Choice chcLevel;
  private Label lblLevel;
  private CheckboxGroup cbgColor;
  private Panel pnlColor;
  private Checkbox cbxWhite;
  private Checkbox cbxBlack;
  private Label lblColor;
  private List lstHelpMoves;
  private Button btnEdit;
  private CheckboxGroup cbgEdit;
  private Panel pnlEdit;
  private Checkbox cbxEmpty;
  private Checkbox cbxManWhite;
  private Checkbox cbxKingWhite;
  private Checkbox cbxManBlack;
  private Checkbox cbxKingBlack;
  private Button btnStart;
  private Button btnHelp;
  private Button btnAbout;
  private Panel pnlButtons;
  private Panel pnlInfoAndButtons;
  private Panel pnlHelpEdit;
  private Panel pnlLeft;
  private Panel pnlRight;
  private Panel pnlHelp;

public Move makePlayerMove(Vector boxList) {
  Move m = new Move();
  Move cur;  
    
    m.from = state.status[ ((Integer)boxList.elementAt(0)).intValue()];
    cur = m;
    
    for( int i=1; i<boxList.size(); i++) {
		cur.toNextJump = new Move();
		cur.to = state.status[((Integer)boxList.elementAt(i)).intValue()];
		cur.toNextJump.from = cur.to;
		cur = cur.toNextJump;
    }
    
    return m;
}

public void resetGame() {
    
    if(editMode == true) {
    	setEditMode();
    }
    state = new State();
    playerMove = new Move();
    computerMove = new Move();
    cur = new Move();
    listOfMoves.removeAllElements();
    listOfCompMoves.removeAllElements();
    cnvBoard.paintComputerMove.removeAllElements();
    lstHelpMoves.removeAll();
    gameStarted = false;
    boxSelected.removeAllElements();
    refreshApplet();
    
}

public void refreshApplet() {
  int i;
    
    for(i=0; i<32 ; i++) {
    	cnvBoard.paintState[i] = state.status[i].getPiece();
    }
    cnvBoard.repaint();
}

public int changePlayer(int player) {
    
    if(player == CheckersGlobal.WHITE) {
    	return CheckersGlobal.BLACK;
    }
    return CheckersGlobal.WHITE;
}

public void playerPlay() {
    
    cnvBoard.animation = false;
    cnvBoard.selectedBox.removeAllElements();		    
    lblStatus.setText("La tua mossa è : "+playerMove.toString());
    state.doMove(playerMove,true);
    boxSelected.removeAllElements();
    refreshApplet();
}

public int alfaBeta(int player, int ply, int useCut, int passCut) {
  Vector listOfSons;
  int i;
  Move currentSon;
  int sonScore;

    if(ply == maxPly) {						//1
    	return state.value(computerColor);
    }
    else {									//2
		listOfSons = state.validMoves(player);
		if(listOfSons.isEmpty()) {			//3
			return state.value(computerColor);
		}
		else {								//4
		    for(i=0;i<listOfSons.size();i++) {
				currentSon = (Move)listOfSons.elementAt(i);
				state.save();
				state.doMove(currentSon,true);
				sonScore = -alfaBeta(changePlayer(player),ply+1,-passCut,-useCut);
				state.restore();
				if(sonScore > passCut) {
				    passCut = sonScore;
				}
				if(passCut >= useCut) {
				    return passCut;
				}
		    }
		    return passCut;
		}
    }
}

public void setHelp() {

    if(helpOn == true) {
		btnHelp.setLabel("Aiuto");
		lstHelpMoves.removeAll();
		lstHelpMoves.add("Se vuoi conoscere");
		lstHelpMoves.add("le tue possibili");
		lstHelpMoves.add("mosse premi 'aiuto'");
		helpOn = false;
    }
    else {
		btnHelp.setLabel("No aiuto");
		lstHelpMoves.removeAll();
		for(int i=0;i<listOfMoves.size();i++) {
		    lstHelpMoves.add((((Move)listOfMoves.elementAt(i)).toString()));
		}
		helpOn = true;	
    }

}

public void startOrStop() {

    if(gameStarted == false) {
		cnvBoard.animation = true;
		refreshApplet();
		btnStart.setLabel("Fine partita");
		lblStatus.setText("");
		gameStarted = true;
		if(computerColor == CheckersGlobal.WHITE) {
		    findComputerMoves();
		    findPlayerMoves();
		}
		else {
		    findPlayerMoves();
		}
    }
    else {
		resetGame();
		gameStarted = false;
		cnvBoard.animation = false;
		btnStart.setLabel("Inizio Partita");
		lblStatus.setText("Inizia sempre il bianco --- Premi inizio partita");
    }
}

public void setEditMode() {

    if(editMode == true) {	  //exit edit mode
		editMode = false;
		cnvBoard.animation = true;
		lblStatus.setText("");
		btnEdit.setLabel("Edita");
		((CardLayout)pnlHelpEdit.getLayout()).show(pnlHelpEdit,"HELP");
		findPlayerMoves();
    }
    else {   //enter edit mode
		if(gameStarted == true) {
		    editMode = true;
		    cnvBoard.animation = false;
		    btnEdit.setLabel("Fine edita");
		    ((CardLayout)pnlHelpEdit.getLayout()).show(pnlHelpEdit,"EDIT");
		    lblStatus.setText("Edita la tua configurazione");
		}
		else {
		    lblStatus.setText("Prima di editare la configurazione premi Inizio partita");
		}
    }   
    repaint();
}

public Move computerPlay() {
  int i;
  Move currentMove;
  Move maxMove = null;
  int maxMoveScore = Integer.MIN_VALUE;
  int currentMoveScore;

    if(listOfCompMoves.size() == 1) {
    	maxMove = (Move)listOfCompMoves.elementAt(0);
    }
    else {
		for(i=0;i<listOfCompMoves.size();i++) {
		    currentMove = (Move)listOfCompMoves.elementAt(i);
		    state.save();
		    state.doMove(currentMove,true);
		    currentMoveScore = alfaBeta(playerColor,1,Integer.MAX_VALUE,Integer.MIN_VALUE);
		    if(currentMoveScore >= maxMoveScore) {
				maxMoveScore = currentMoveScore;
				maxMove = currentMove;
		    }
		    state.restore();
		}
    }
    return maxMove;
}

public void init() {

//inizializzo le variabili
    state = new State();

    listOfMoves = new Vector();
    listOfCompMoves = new Vector();
    playerMove = Move.NOMOVE;
    computerMove = Move.NOMOVE;
    cur = Move.NOMOVE;
    gameStarted = false;
    playerColor = CheckersGlobal.WHITE;
    computerColor = CheckersGlobal.BLACK;
    editMode = false;
    maxPly = 3;
    images = new Image[8];
    boxSelected = new Vector();
    helpOn = true;

//creo i componenti grafici

 //label
    lblTitle = new Label("Abt Dama Italiana", Label.LEFT);
    lblStatus = new Label("Inizia sempre il bianco", Label.LEFT);
    lblLevel = new Label("Livello di difficoltà");
    lblColor = new Label("Il tuo colore è il BIANCO");
    lblHelpMoves = new Label("Le tue possibili mosse");
    
 //canvas
    cnvBoard = new CanvasCheckersBoard();
    
 //panel
    pnlCanvas = new Panel();
    pnlLevel = new Panel();
    pnlColor = new Panel();
    pnlEdit = new Panel();
    pnlHelp = new Panel();
    pnlHelpEdit = new Panel();
    pnlButtons = new Panel();
    pnlInfoAndButtons = new Panel();
    pnlLeft = new Panel();
    pnlRight = new Panel();
    
 //choice
    chcLevel = new Choice();
    
 //checkboxgroup
    cbgColor = new CheckboxGroup();
    cbgEdit = new CheckboxGroup();
    
 //checkbox
    cbxWhite = new Checkbox("Bianco", cbgColor, true);
    cbxBlack = new Checkbox("Nero", cbgColor, false);
    cbxEmpty = new Checkbox("Casella vuota", cbgEdit, false);
    cbxManWhite = new Checkbox("Pedina bianca", cbgEdit, false);
    cbxManBlack = new Checkbox("Pedina nera", cbgEdit, false);
    cbxKingWhite = new Checkbox("Dama bianca", cbgEdit, false);
    cbxKingBlack = new Checkbox("Dama nera", cbgEdit, true);
    
 //list
    lstHelpMoves = new List(7, false);
    lstHelpMoves.add(" ");
    
 //button
    btnEdit = new Button("Modo edit");
    btnStart = new Button("Inizio partita");
    btnHelp = new Button("No aiuto");
    btnAbout = new Button("About");
            
//carica le immagini 
    images[CheckersGlobal.TOTALBOARD] = getImage(getCodeBase(),"TotalBoard.gif");
    images[CheckersGlobal.EMPTYBLUE] = getImage(getCodeBase(),"EMPTYBLUE.gif");
    images[CheckersGlobal.SELECTION] = getImage(getCodeBase(),"SELECTION.gif");
    images[CheckersGlobal.MANWHITE] = getImage(getCodeBase(),"MANWHITE.gif");
    images[CheckersGlobal.MANBLACK] = getImage(getCodeBase(),"MANBLACK.gif");
    images[CheckersGlobal.KINGWHITE] = getImage(getCodeBase(),"KINGWHITE.gif");
    images[CheckersGlobal.KINGBLACK] = getImage(getCodeBase(),"KINGBLACK.gif");
    
    cnvBoard.images = this.images;
    
//posiziono i componenti grafici

 //canvas
    pnlCanvas.setLayout(new FlowLayout());
    pnlCanvas.add(cnvBoard);
    
 //panel level
    chcLevel.addItem("Livello 1 (Facile)");
    chcLevel.addItem("Livello 2");
    chcLevel.addItem("Livello 3");
    chcLevel.addItem("Livello 4");
    chcLevel.addItem("Livello 5");
    
    pnlLevel.setLayout(new BorderLayout());
    pnlLevel.add("North", lblLevel);
    pnlLevel.add("South", chcLevel);
    
 //panel color
    pnlColor.setLayout(new BorderLayout());
    pnlColor.add("North", lblColor);
    pnlColor.add("West", cbxWhite);
    pnlColor.add("East", cbxBlack);
    
 //panel edit
    pnlEdit.setLayout(new GridLayout(5,1));
    pnlEdit.add(cbxManWhite);
    pnlEdit.add(cbxKingWhite);
    pnlEdit.add(cbxManBlack);
    pnlEdit.add(cbxKingBlack);
    pnlEdit.add(cbxEmpty);
    
 //panel help
    pnlHelp.setLayout(new BorderLayout());
    pnlHelp.add("North", lblHelpMoves);
    pnlHelp.add("Center", lstHelpMoves);
    
 //panel helpedit
    pnlHelpEdit.setLayout(new CardLayout());
    pnlHelpEdit.add("HELP", pnlHelp);
    pnlHelpEdit.add("EDIT", pnlEdit);

    
 //panel buttons
    pnlButtons.setLayout(new GridLayout(0,4));
    pnlButtons.add(btnStart);
    pnlButtons.add(btnEdit);
    pnlButtons.add(btnHelp);
    pnlButtons.add(btnAbout);

 //panel infoandbuttons
    pnlInfoAndButtons.setLayout( new BorderLayout());
    pnlInfoAndButtons.add("North",lblStatus);
    pnlInfoAndButtons.add("Center",pnlButtons);

 //panel left
    pnlLeft.setLayout( new BorderLayout());
    pnlLeft.add("North", lblTitle);
    pnlLeft.add("Center", cnvBoard);
 //   pnlLeft.add("South", lblStatus);
 
 //panel right
    GridBagConstraints gridConstraints = new GridBagConstraints();
    GridBagLayout gridBag = new GridBagLayout();
    pnlRight.setLayout(gridBag);
    gridConstraints.gridx = 0;
    gridConstraints.gridy = 0;
    gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
    gridConstraints.gridheight = 2;
    gridConstraints.weightx = 1;
    gridConstraints.weighty = 1;
    gridBag.setConstraints(pnlColor, gridConstraints);
    pnlRight.add(pnlColor);
    gridConstraints.gridy = 2;
//    gridConstraints.fill = GridBagConstraints.HORIZONTAL;
    gridBag.setConstraints(pnlLevel, gridConstraints);
    pnlRight.add(pnlLevel);
    gridConstraints.gridy = 4;
    gridConstraints.gridheight = 4;
 //   gridConstraints.fill = GridBagConstraints.VERTICAL;
//    gridConstraints.weightx = 0.5;
    gridBag.setConstraints(pnlHelpEdit, gridConstraints);
    pnlRight.add(pnlHelpEdit);
    gridConstraints.gridy = 8;
    gridConstraints.gridheight = 2;
 //   gridConstraints.fill = GridBagConstraints.HORIZONTAL;
//    gridConstraints.weightx = ;
 //   gridBag.setConstraints(lblStatus, gridConstraints);
 //   pnlRight.add(lblStatus);

 //metto tutto insieme
    setLayout( new BorderLayout());
    add("West", pnlLeft);
    add("East", pnlRight);
    add("South", pnlInfoAndButtons);
    
    registerEventHandlers();
      
}

private void handleMouseDown(int x, int y) {

    if(cnvBoard.userSelection != CheckersGlobal.UNDEF && gameStarted == true) {
		if(editMode == false) {
		    boxSelected.addElement( new Integer( cnvBoard.userSelection));
		    if( boxSelected.size() == 1 ) {
				refreshApplet();
				lblStatus.setText( "Seleziona la prossima casella " + (cnvBoard.userSelection + 1) + " -> ");
		    }
		    refreshApplet();
		    playerMove = makePlayerMove(boxSelected);
	
		    try {
				if(playerMove.isValid(listOfMoves)) {
				    playerPlay();
				    findComputerMoves();
				    cnvBoard.animation = true;
				    findPlayerMoves();
				}
				else {
				    badPlayerMove();
		
				}
		    } catch(NullPointerException e) { 
			    lblStatus.setText("Seleziona la prossima casella "+playerMove.toString()); 
			    lblStatus.repaint();
			}		
		}
		else {
		    int pieceType = CheckersGlobal.EMPTYBLUE;
		
		    if(cbgEdit.getSelectedCheckbox() == cbxManWhite) 
			pieceType = CheckersGlobal.MANWHITE;
		    if(cbgEdit.getSelectedCheckbox() == cbxManBlack) 
			pieceType = CheckersGlobal.MANBLACK;
		    if(cbgEdit.getSelectedCheckbox() == cbxKingWhite) 
			pieceType = CheckersGlobal.KINGWHITE;
		    if(cbgEdit.getSelectedCheckbox() == cbxKingBlack) 
			pieceType = CheckersGlobal.KINGBLACK;
		    if(cbgEdit.getSelectedCheckbox() == cbxEmpty) 
			pieceType = CheckersGlobal.EMPTYBLUE;
		    state.status[cnvBoard.userSelection].setPiece(pieceType);	    
		    
		    refreshApplet();
		}
    }       
}

public void badPlayerMove() {
 
    lblStatus.setText("MOSSA NON VALIDA !!! "+playerMove.toString());

    playerMove = new Move(); 
    boxSelected.removeAllElements();
    cnvBoard.selectedBox.removeAllElements();	  
    refreshApplet();
}

public void findComputerMoves() {
    
    listOfCompMoves = state.validMoves(computerColor);
    if(listOfCompMoves.isEmpty()) {
    	lblStatus.setText("----HAI VINTO----");
    	startOrStop();
    }
    else {
    	lblStatus.setText(lblStatus.getText() + " --- Sto elaborando la mia mossa");
    	lblStatus.repaint();
		computerMove = computerPlay();
		state.doMove(computerMove, true);
		cnvBoard.paintComputerMove = computerMove.toVector();
		refreshApplet();
		lblStatus.setText("La mossa del computer è : "+computerMove.toString());
		lblStatus.repaint();
    }
}

public void findPlayerMoves() {
  int i;
    
    listOfMoves = state.validMoves(playerColor);
     
    if(listOfMoves.isEmpty()) {
    	lblStatus.setText("----HAI PERSO----");
    	startOrStop();
    }
    else {
		lblStatus.setText(lblStatus.getText() + " --- Fai la tua mossa");
		if((helpOn == true) && (gameStarted == true)) {
		    lstHelpMoves.removeAll();
		    for(i=0;i<listOfMoves.size();i++) {
		    	lstHelpMoves.add((((Move)listOfMoves.elementAt(i)).toString()));
		    }
		}
		playerMove = new Move();
    }
}

public void setPlayerColor(int color) {
    
    if(color == CheckersGlobal.WHITE) {
		playerColor = CheckersGlobal.WHITE;
		computerColor = CheckersGlobal.BLACK;
		lblColor.setText("Il tuo colore � il BIANCO");
    }
    else {
		playerColor = CheckersGlobal.BLACK;
		computerColor = CheckersGlobal.WHITE;
		lblColor.setText("Il tuo colore � il NERO");
    }
    findPlayerMoves();
}

//public void paint(Graphics g) {
//}

public void update(Graphics g) {
    paint(g);
}

private void registerEventHandlers() {
	
    btnEdit.addActionListener(new ActionListener() {

		public void actionPerformed(ActionEvent e) {
			setEditMode();			
		}    	
    });    
    
    btnStart.addActionListener(new ActionListener() {

		public void actionPerformed(ActionEvent e) {
			startOrStop();			
		}    	
    });    
    
    btnHelp.addActionListener(new ActionListener() {

		public void actionPerformed(ActionEvent e) {
			setHelp();			
		}    	
    });
    
    btnAbout.addActionListener(new ActionListener() {

		public void actionPerformed(ActionEvent arg0) {
			lblStatus.setText("Autore Fabio Di Fabio");
		}    	
    });
    
    chcLevel.addItemListener(new ItemListener() {

		public void itemStateChanged(ItemEvent e) {
			maxPly = 3 + 2 * chcLevel.getSelectedIndex();
		}    	
    });
	
    cbxWhite.addItemListener(new ItemListener() {

		public void itemStateChanged(ItemEvent e) {
			if(e.getStateChange() == ItemEvent.SELECTED) {
				setPlayerColor(CheckersGlobal.WHITE);
			}
		}    	
    });
    
    cbxBlack.addItemListener(new ItemListener() {

		public void itemStateChanged(ItemEvent e) {
			if(e.getStateChange() == ItemEvent.SELECTED) {
				setPlayerColor(CheckersGlobal.BLACK);
			}
		}    	
    });
    
    cnvBoard.addMouseListener(new MouseAdapter() {

		public void mouseClicked(MouseEvent e) {
			handleMouseDown(e.getX(), e.getY());
			super.mouseClicked(e);
		}
    });
}

}
